﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using AutoMapper;
using Cache.CSRedis;
using Common.Tools;
using Common.Tools.Filter;
using Common.Tools.Logger;
using EventBus.Common;
using EventBus.RabbitMQ;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.PlatformAbstractions;
using Microsoft.OpenApi.Models;
using Product.Application;
using Product.Application.Query;
using Product.Common;
using Product.Domain.DomainService;
using Product.Domain.Repository;
using Product.EntityFrameworkCore;
using Product.EntityFrameworkCore.Repository;
using ProductWebApi.IntegratedEventService;
using WebApiClient;
using ILoggerFactory = Microsoft.Extensions.Logging.ILoggerFactory;
using WebApi.Swagger;
namespace ProductWebApi
{
    /// <summary>
    /// 依赖注入配置
    /// </summary>
    public class DependencyInjectionService
    {
        private static DependencyInjectionService _dependencyInjectionConfiguration;
        private static readonly object LockObj = new object();
        private static IServiceCollection _services;

        /// <summary>
        /// 单例模式
        /// </summary>
        /// <returns></returns>
        public static DependencyInjectionService GetInstance(IServiceCollection services)
        {
            _services = services;
            if (_dependencyInjectionConfiguration == null)
            {
                lock (LockObj)
                {
                    if (_dependencyInjectionConfiguration == null)
                    {
                        _dependencyInjectionConfiguration = new DependencyInjectionService();
                    }
                }
            }
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加AddDbContextPool
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddDbContextPool(IConfiguration configuration)
        {
            //注入配置文件
            _services.TryAddSingleton(new ConfigurationHelper(configuration));

            //EF日志
            ILoggerFactory efLoggerFactory
               = LoggerFactory.Create(builder =>
               {
                   builder
                       .AddFilter((category, level) =>
                           category == DbLoggerCategory.Database.Command.Name
                           && level == LogLevel.Information)
                       .AddConsole();
               });
            var databaseType = ConfigurationHelper.GetDatabaseType();
            //读取数据库连接字符串
            var connectionString = ConfigurationHelper.GetConnectionString();
            switch (databaseType)
            {
                case DatabaseType.SqlServer:

                    //使用DbContext连接池，poolSize不能超过100，
                    _services.AddDbContextPool<Product.EntityFrameworkCore.ProductContext>(
                        options => options.UseSqlServer(connectionString)//连接异常时重试次数
                                                                         //.AddInterceptors(new HintCommandInterceptor(_services))//ef 拦截器
                            .UseLoggerFactory(efLoggerFactory)//ef 日志记录
                            .UseLazyLoadingProxies(),
                        poolSize: 100);
                    break;
                case DatabaseType.Mysql:
                    //使用DbContext连接池，poolSize不能超过100，
                    _services.AddDbContextPool<Product.EntityFrameworkCore.ProductContext>(
                        options => options.UseMySql(connectionString, s => s.EnableRetryOnFailure(5))//连接异常时重试次数
                                                                                                     //.AddInterceptors(new HintCommandInterceptor(_services))//ef 拦截器
                            .UseLoggerFactory(efLoggerFactory)//ef 日志记录
                            .UseLazyLoadingProxies(),
                        poolSize: 100);
                    break;
                default:
                    break;
            }
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加MVC
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddMvc()
        {
            _services.AddControllers(options =>
            {
                options.Filters.Add(typeof(ExceptionFilter)); 
                options.Filters.Add(typeof(AuthorizationFilter)); 

            }).AddJsonOptions(options =>
            {
                //忽略循环引用
                //options.JsonSerializerOptions.IgnoreReadOnlyProperties = true;
            });
            //    .AddFluentValidation(options =>
            //{
            //    //options.RunDefaultMvcValidationAfterFluentValidationExecutes = false;
            //    //var validatorList = GetFluentValidationValidator("OrderContext");
            //    //foreach (var item in validatorList)
            //    //{
            //    //    options.RegisterValidatorsFromAssemblyContaining(item);
            //    //}
            //});
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 获取所有的FluentValidation Validator的类
        /// </summary>
        public IEnumerable<Type> GetFluentValidationValidator(string assemblyName)
        {
            if (assemblyName == null)
                throw new ArgumentNullException(nameof(assemblyName));
            if (string.IsNullOrEmpty(assemblyName))
                throw new ArgumentNullException(nameof(assemblyName));

            var implementAssembly = Common.Tools.RuntimeHelper.GetAssembly(assemblyName);
            if (implementAssembly == null)
            {
                throw new DllNotFoundException($"the dll ConferenceWebApi not be found");
            }
            var validatorList = implementAssembly.GetTypes().Where(e => e.Name.EndsWith("Validator"));
            return validatorList;
        }

        /// <summary>
        /// 添加Cookie
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddCookie()
        {
            //注册Cookie认证服务
            _services.AddAuthentication(option =>
                {
                    option.DefaultChallengeScheme = "Cookie";
                    option.DefaultAuthenticateScheme = "Cookie";
                }).AddCookie();
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加CAP
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddCap()
        {
            //_services.AddCap(x =>
            //{
            //    // 如果你的 SqlServer 使用的 EF 进行数据操作，你需要添加如下配置： 
            //    //x.UseEntityFramework<Product.EntityFrameworkCore.ProductContext>();
            //    //x.UseSqlServer("Data Source=DESKTOP-G8UTIT6\\LI;Initial Catalog=Conference;User ID=sa;Password=123456li;MultipleActiveResultSets=true");
            //    //启用操作面板
            //    x.UseDashboard();

            //    // 如果你使用的 RabbitMQ 作为MQ，你需要添加如下配置：              
            //    x.UseRabbitMQ(cfg =>
            //    {
            //        cfg.HostName = "47.104.83.210";
            //        cfg.UserName = "lifeng";
            //        cfg.Password = "lifeng123";
            //    });
            //    //设置失败重试次数
            //    x.FailedRetryCount = 50;
            //});
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加跨域
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddCors()
        {
            //配置跨域处理
            _services.AddCors(options =>
            {
                options.AddPolicy("any", builder =>
                {
                    builder.AllowAnyOrigin() //允许任何来源的主机访问
                        .AllowAnyMethod()
                        .AllowAnyHeader()
                        .AllowCredentials();//指定处理cookie
                });
            });
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加Swagger
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddSwagger(IConfiguration configuration)
        {
            _services.AddExtensionSwagger(configuration);

            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加DDD分层的注入
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddDddLayering()
        {
            // 使用Mapper
            _services.AddAutoMapper(typeof(AutomapperConfig));

            //注入ExceptionLessLogger服务
            _services.AddSingleton<ILoggerHelper, ExceptionLessLogger>();

            //批量注入仓储Repository
            _services.AddScoped<ISkuReposiory, SkuReposiory>();
            _services.AddScoped<ISpuReposiory, SpuReposiory>();
            //_services.RegisterAssembly("Order.Domain", "Order.EntityFrameworkCore");

            //注入工作单元
            _services.AddScoped<IUnitOfWork, UnitOfWork>();

            //批量注入领域服务DomainService
            _services.AddScoped(typeof(SpuDomainService));
            //_services.RegisterDomainServiceAssembly("Order.Domain");   
            
            _services.AddScoped<ISkuQueryService, SkuQueryService>();
            ////批量注入应用服务Service
            _services.AddScoped<ISpuAppService, SpuAppService>();
            //_services.RegisterAssembly("Order.CommandHandler");
            _services.AddSingleton<IEventHandler<DeductionStockEvent>, DeductionStockService>();
            ////注入EventBus
            //_services.AddSingleton<IOptions<RabbitMQOptions>>(new RabbitMQOptions { HostName = "47.104.83.210", UserName = "lifeng", Password = "lifeng123" });
            //_services.AddSingleton<IConnectionChannel, ConnectionChannel>();
            //_services.AddSingleton<IRabbitMqPublisher, RabbitMqPublisher>();
            //_services.AddSingleton<IRabbitMqSubscriber, RabbitMqSubscriber>();

            //注入CommandService
            //_services.AddSingleton<ICommandService, CommandService>();
            //_services.AddSingleton<IntegratedEventService, IintegratedEventService>();
            ////注入RabbitmqEventBus
            //_services.RegisterHandler("Order.CommandHandler");
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加Redis
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddRedis()
        {
            RedisOptions options = new RedisOptions
            {
                HostName = "47.104.83.210",
                Port = 6379,
                Password = "abcdefg123456",
                DefaultDatabase = string.Empty,
                WriteBuffer = 10240,
                Prefix = string.Empty,
                TryIt = 3,
                PoolSize = 50,
                SSL = false,
                ExpireSeconds = 60,
                EnvName = string.Empty
            };
            _services.TryAddSingleton<IOptions<RedisOptions>>(options);
            _services.TryAddSingleton<IRedisHelper, CsRedisHelper>();
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加AddFluentValidationErrorMessage
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddFluentValidationErrorMessage()
        {
            _services.Configure<ApiBehaviorOptions>(options =>
            {
                options.InvalidModelStateResponseFactory = (context) =>
                {
                    var errors = context.ModelState
                        .Values
                        .SelectMany(x => x.Errors
                                    .Select(p => p.ErrorMessage))
                        .ToList();

                    return new ContentResult()
                    {
                        StatusCode = (int)HttpStatusCode.InternalServerError,
                        Content = string.Join(",", errors.Select(e => string.Format("{0}", e)).ToList())
                    };
                };
            });
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加WebApiClient
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddWebApiClient<T>(string url) where T : class, IHttpApi
        {
            _services.AddSingleton<IHttpApiFactory<T>, HttpApiFactory<T>>(p =>
            {
                return new HttpApiFactory<T>().ConfigureHttpApiConfig(c =>
                {
                    c.HttpHost = new Uri(url);
                    c.LoggerFactory = p.GetRequiredService<ILoggerFactory>();
                });
            });

            _services.AddTransient(p =>
            {
                var factory = p.GetRequiredService<IHttpApiFactory<T>>();
                return factory.CreateHttpApi();
            });

            return _dependencyInjectionConfiguration;
        }

    }
}
